home *** CD-ROM | disk | FTP | other *** search
- Ry.use, a tutorial on the use of the random file code.
-
- Ry.c consists of a set of functions that allow direct random access of
- a disk file. This access is on a byte addressable level, using 'long integers'
- as provided in BDS C by the long.c functions. The base functions are 'rgetc()'
- and 'rputc()'. All other character handling functions (i.e. 'rprintf()') are
- built upon these two. For details of calling conventions, etc. refer to the
- file 'ry.doc'. One inportant detail, this code requires a z-80 processor to
- run.
-
- Internally, a file created by the ry code ('rcreat()') is identical to
- any other cp/m text file with one exception. The first sector (known as sector
- '0' to cp/m) is reserved as a file header for use by 'rcreat()', 'ropen()',
- etc. As such, the 'first' byte of a file comes from and goes to the first byte
- of sector 1. This offset is maintained throught the file. This is only
- important, however, if you use other tools (such as ddt) to diddle with a
- random file. Requests to seek any byte automatically add this offset to the
- argument. Using the cpm command 'type' will also cause some interesting
- results since the header (sector 0) will typically contain integer values that
- will send the console into a fit. And if a 0x1a (^z) exists anywhere in the
- header you will never even see the file proper. This inconvenience is
- justified in most cases by the added power that this header allows when
- handeling files in a random fashion.
-
- The first half of this header, i.e. 64 bytes, is reserved for use by
- 'rcreat()', 'ropen()', and 'rclose()'. The first 4 bytes are for a long
- integer pointer to the EOF. The ry code presently DOES NOT AUTOMATICALLY place
- this value for you. It is the programmers responsibility to do so, if this
- information is needed for the next time that the file is used. Future versions
- will take care of this also. Bytes 5-8 are reserved for a timestamp of the
- date of file creation, bytes 9-12 for a timestamp of the date of last access.
- Again, these fields are not yet filled by the present version of ry code. The
- remaining bytes of the first half are as yet undefined but reserved.
-
- The second half of the header is for use by the programmer in any way
- that he/she wishes. Typically it might contain links to other files, or
- perhaps pointers used to separate different logical parts of a file.
-
- When a file is opened via 'ropen()' or 'rcreat()' the function call
- returns a pointer to a structure of type _file. This pointer is used by all
- random function calls to refer to the file. In 'ry.h' a #define equates the
- string "RFILE" to "struct _file", thus you declare a variable to hold the
- returned value of 'ropen()' or 'rcreat()' as RFILE *<variable_name>. What you
- are doing is declaring the variable to be a pointer to an 'RFILE' or 'struct of
- type _file'.
-
- As an example, let's create a file to hold to hold a list of names.
- First we declare the variable used to hold the file pointer as:
-
- RFILE *foo;
-
- Next we creat the file:
-
- foo = rcreat("a:namefile", 'd', 8);
-
- The first arg is obvious, the name of the file we wish to create. The
- second arg is a char that defines the mode in which we want the file to be
- created/opened. In this case we used a 'd' to ask that the file be opened for
- 'direct' (read and write) access. Other modes include 'r' for read only and
- 'w' for write only. The unix file mode 'a' (append) is not implimented yet.
- The third arg is the number of sectors that you want the system to use for
- buffering the file. A large number here speeds things up by cutting down on
- the number of disk accesses, but at the cost of using a large amount of memory.
- Remember that this number refers to logical cp/m sectors, size of 128 bytes.
- In this example I used 8 so that exactly 1 physical sector (my bios uses 1k
- sectors) would be buffered, thus optimizing disk reads.
-
- The syntax is identical for 'ropen()'. A file may be opened with a
- different declared access mode and buffersize than that used when it was
- created. The file pointer (foo in this case) is used as an arg for all other
- references to this file. It is the sole arg to 'rclose()'. Be sure to check
- the file pointer for a value of ERROR (-1) when opening or creating a file. If
- an ERROR is returned DO NOT 'rclose()' the file, this will bash the system!
- This is because of the fact that 'rclose()' returns bufferspace to the dynamic
- memory pool maintained by 'alloc()' and 'free()'. This brings up one more
- important point, BE SURE TO HAVE THE STATEMENT '_allocp = NULL;' as the first
- item of any program using ry functions. This also means that alloc() and
- free() must be enabled in your std libraries.
-
- Next, let's add a couple names to the file:
-
- rputs("freddy fudd", foo);
- rputs("sally sue", foo);
-
- Here the first arg is the string that we want to put in the file, and
- the second is the file pointer. Ry.doc gives details for the use of other
- calls such as 'rputl()' and 'rprintf()'. All of the commands for getting
- things back out are also documented there.
-
- To retrieve the names we first have to get back to the begginning of
- the file:
-
- lseek(foo, "0", 3);
-
- The first arg is obviously the file pointer. The second is the byte we
- want, expressed as an ascii string. The third arg tells 'lseek()' that the
- second arg is a pointer to an ascii representation of the sought after byte.
-
- The possible values for the third arg are:
-
- a: 0, (used above) meaning that the second arg is the address of a 4
- byte array holding a 'long int', the value of which is the address of the byte
- we want to access. This address is relative to the first byte of the file.
-
- b: 1, as in 0 above, the second arg is an array holding a 'long int',
- but this time the address it represents is relative to the present location in
- the file.
-
- c: 2 is reserved for 'relative to end of file', not implimented yet.
-
- d: 3 means that the second arg is the address of an array holding an
- ascii representation of the byte address we want to access. 'lseek()' converts
- this string into the appropriate value before seeking the byte address.
-
- e: 4, same as 3, but address is relative to present location in file
- (as in 1).
-
- f: 5, reserved for 'ascii relative from end of file', not implimented
- yet.
-
- Now that we have sought byte 0 from beginning of file we can reread it.
-
- char firstname[30], secondname[30]; /* declare strings to hold names */
-
- rgets(firstname, foo);
- rgets(secondname, foo);
-
- The first arg is the destination of the string, the second the file
- pointer.
-
- Next we might want to mark the EOF:
-
- rputc(0x1a, foo);
-
- This just placed a control z in the file, following the NULL byte that
- terminated the string "sally sue".
-
- Next we want to back up 1 byte so that we are at the '^z':
-
- lseek(foo, "-1", 3)
-
- We asked to go back 1 byte from the present file location. We are now
- in the file at the position of the '^z' byte following the string "sally sue".
- We could record this position in the file header by:
-
- ltell(foo, foo + 1);
-
- The first arg is the file pointer, the second is the address of a 4
- byte array that we want a 'long int' to be placed. This 'long int' is the
- address of the current position in the file. When a file is opened the header
- kept in sector 0 is placed in the buffer, between the struct that describes
- the file and the buffered file data. The first four bytes of this header are
- reserved for the EOF address, thus we ask 'ltell()' to place the current file
- position (1 byte beyond the ^z) into the first 4 bytes following the struct
- pointed at by foo. Remember that foo is a pointer to a struct of type _file,
- thus 'foo + 1' evaluates to the address following the struct, not 1 byte beyond
- the beginning of foo! Note that there is no way to make 'ltell()' return an
- ascii form of the address. You would have to use 'ltoa()' to make this
- conversion if needed.
-
- Now to close the file:
-
- rclose(foo);
-
- This causes the buffer to be flushed to the disk if necessary and the
- header to be updated to disk. Thus the address of the EOF has been recorded,
- we need not read the whole file next time to find the end. After opening it we
- merely:
-
- lseek(foo, foo + 1, 0);
-
- Here we told 'lseek()' to seek the address held in the first 4 bytes of
- the header, that address being a 'long int', relative to beginning of the file.
-
- Here's a complete program to help illustrate some of these ideas. It
- is used to creat an empty mailbox used by a networking program. It first tries
- to open the file, if successful it terminates the program, not wanting to
- destroy the current box. Otherwise it creates the file and puts a ^z in the
- first byte to mark the EOF. It then records the EOF address in the header by
- moving 4 zeros (a long int of 0) into the slot reserved for this value. It
- could have also done an 'ltell()' as we did above. It closes and is done.
-
-
- #include "a:std.h"
- #include <ry.h>
- main()
- {
- RFILE *op_mbx;
-
- _allocp = NULL;
-
- if ((op_mbx = ropen("a:sysop.mbx", 'd', 2)) != ERROR) {
- printf("\n\tI already have one....");
- rclose(op_mbx);
- exit();
- }
- if ((op_mbx = rcreat("a:sysop.mbx", 'd', 2)) == ERROR) {
- printf("\n\tCan't, problems with sysop's mailbox, sorry.");
- exit();
- }
- rputc(0x1a, op_mbx); /* put ^z at end for cp/m */
- setmem(op_mbx + 1, 0, 4); /* put pos. 0 at EOF slot */
- rclose(op_mbx);
- }
-
- See chapter 8, The Unix System Interface, of The C Programming Language for more info on random file use.
-
- Along with the ry code you will also need the 'lx.crl' file, which
- contains the long int functions. Several additions/corrections to the original
- cug release of long.c are included in this file. Remember that you need a z-80
- to run the long int package. The alternative would be to rewrite 'li()' in
- 8080 .csm code.
- lue.